#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2025/11/1 15:42
# @Author  : summer
# @Email   : 610658552@qq.com
# @File    : util_ip.py
# @Software: PyCharm
# @Desc    : IP归属地查询工具库

import logging
import sys
from typing import Optional, Dict

import requests
from requests.exceptions import RequestException, Timeout, ConnectionError

# -------------------------- 基础配置 --------------------------
# 初始化日志（命令行运行时输出到控制台，便于测试）
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[logging.StreamHandler()]
)
logger = logging.getLogger('utils.ip_utils')

# IP查询接口配置（可替换为其他接口）
IP_QUERY_URL = "http://ip-api.com/json/{ip}?lang=zh-CN"
TIMEOUT = 3  # 超时时间（秒）
LOCAL_IPS = ['127.0.0.1', '0.0.0.0', 'localhost', '::1']  # 本地IP标识
DEFAULT_LOCATION = "未知区域"  # 查询失败默认值


def get_ip_address(ip: str) -> str:
    """
    核心功能：根据IP地址查询归属地（城市级别）
    :param ip: 客户端IP地址（字符串格式）
    :return: 格式化归属地（如：中国-广东省-广州市）
    """
    # 1. 过滤本地IP/空IP
    if not ip or ip.strip().lower() in LOCAL_IPS:
        logger.debug(f"[过滤] IP {ip} 为本地IP/空IP，无需查询")
        return "本地开发环境"

    clean_ip = ip.strip()
    query_url = IP_QUERY_URL.format(ip=clean_ip)

    try:
        # 2. 发送查询请求
        logger.debug(f"[请求] 调用IP查询接口：{query_url}")
        response = requests.get(query_url, timeout=TIMEOUT)
        response.raise_for_status()  # 非200状态码抛异常

        # 3. 解析响应结果
        result = response.json()
        if result.get("status") == "success":
            country = result.get("country", "未知国家")
            region = result.get("regionName", "未知省份")
            city = result.get("city", "未知城市")
            location = f"{country}-{region}-{city}"
            logger.info(f"[成功] IP {clean_ip} 归属地：{location}")
            return location
        else:
            err_msg = result.get("message", "未知错误")
            logger.warning(f"[接口失败] IP {clean_ip} 查询失败：{err_msg}")
            return DEFAULT_LOCATION

    # 4. 捕获异常
    except Timeout:
        logger.error(f"[超时] IP {clean_ip} 查询超时（超过{TIMEOUT}秒）")
        return DEFAULT_LOCATION
    except ConnectionError:
        logger.error(f"[连接失败] IP {clean_ip} 查询：网络不可用/接口无法连接")
        return DEFAULT_LOCATION
    except RequestException as e:
        logger.error(f"[HTTP异常] IP {clean_ip} 查询：{str(e)}", exc_info=True)
        return DEFAULT_LOCATION
    except Exception as e:
        logger.critical(f"[未知异常] IP {clean_ip} 查询：{str(e)}", exc_info=True)
        return DEFAULT_LOCATION


def get_ip_location(ip: str) -> Dict[str, Optional[str]]:
    """
    增强版IP定位：返回城市、省份、经纬度
    :param ip: 待查询IP
    :return: 包含城市、省份、经度、纬度的字典
    """
    try:
        # 调用免费IP定位API（支持经纬度返回）
        response = requests.get(
            f"https://ipapi.co/{ip}/json/",
            timeout=5,
            headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
        )
        response.raise_for_status()
        data = response.json()

        # 提取核心字段（兼容内网IP/无效IP）
        return {
            "city": data.get("city") or "未知城市",
            "region": data.get("region") or "未知省份",
            "longitude": data.get("longitude") or None,  # 经度
            "latitude": data.get("latitude") or None,  # 纬度
            "ip": ip
        }
    except Exception as e:
        logger.error(f"IP定位失败（{ip}）：{str(e)}")
        return {
            "city": "定位失败",
            "region": "未知区域",
            "longitude": None,
            "latitude": None,
            "ip": ip
        }


def main():
    """
    命令行测试入口：直接运行 ip_utils.py 自动执行查询（无需手动传参）
    逻辑：固定测试2个IP（本地IP+公网IP），自动输出查询结果
    """
    # 1. 定义固定测试IP列表（可根据需求修改，支持多个IP批量测试）
    # 包含本地IP（验证过滤逻辑）和公网IP（验证正常查询逻辑）
    test_ips = [
        "127.0.0.1",  # 本地IP（预期返回“本地开发环境”）
        "114.114.114.114",  # 公网IP（预期返回具体城市，如“中国-江苏省-南京市”）
        "8.8.8.8"  # 国外IP（预期返回“美国-加利福尼亚州-山景城”）
    ]

    logger.info("=== 开始IP归属地批量测试（无需手动传参）===")
    # 2. 循环测试每个IP
    for ip in test_ips:
        print(f"\n--- 测试IP：{ip} ---")
        try:
            # 调用查询方法
            location = get_ip_location(ip)
            # 打印结果（格式清晰，便于查看）
            print(f"待查询IP：{ip}")
            print(f"归属地   ：{location}")
            logger.debug(f"IP {ip} 测试完成，结果：{location}")
        except Exception as e:
            # 捕获单个IP测试异常（不中断其他IP测试）
            print(f"IP {ip} 测试失败：{str(e)}")
            logger.error(f"IP {ip} 测试异常：{str(e)}", exc_info=True)

    print("\n=== 所有IP测试完成 ===")


# 命令行运行入口（直接执行该文件时触发）
if __name__ == "__main__":
    # main()
    print(get_ip_location("221.226.103.219"))